Skip to content

Redesign peers list - #889

Open
pseudoramdom wants to merge 5 commits into
bitcoin-core:qt6from
pseudoramdom:peers-redesign
Open

Redesign peers list#889
pseudoramdom wants to merge 5 commits into
bitcoin-core:qt6from
pseudoramdom:peers-redesign

Conversation

@pseudoramdom

@pseudoramdom pseudoramdom commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Summary

The existing Peers interface was designed around a narrow layout and separate list, detail, and banned-peer pages. This redesign presents peer information more consistently, makes better use of wider windows, and adapts the same interaction model to compact layouts. Additionally, add support to search, filter, sort peers.

Implementation details

  • Introduce SizeClass to centralize compact and regular layout breakpoints. Originally proposed in qml: Introduce adaptive sidebar/tab-bar shell driven by size class #690 but felt worthwhile to port it in to this redesign.
  • Introduce NavigationSplitView a reusable primary-detail container. At regular widths, th list and detail view are displayed side by side with the first peer selected automatically. At compact widths, they are stacked in a navigation view.
  • Peers list and detail adopts the NavigationSplitView

Screenshots

Peers.redesign.mp4

Introduce a SizeClass singleton that centralizes compact and regular
width and height breakpoints. Views can use the shared helpers to adapt
their layouts without duplicating breakpoint logic.
Add a reusable primary-detail container that displays both columns at
regular widths and navigates between them at compact widths. Support
configurable column sizing, separators, and animated transitions.

Test regular sizing, compact navigation, full-height separators, and
transitions between size classes.
Expose transport, session, relay, bandwidth, and address-processing
details required by the redesigned peer views.

Add peer search, filtering, sort direction, result counts, and stable
detail-model lookup to the peer list proxy. Cover the additional roles,
formatting, filters, ordering, and peer lookup behavior with unit tests.
Redesign the peer list with search, filters, sorting, traffic details,
and contextual peer actions.

@uqlidi uqlidi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's impressive works. I like the new design but there are few suggestions

@@ -0,0 +1,237 @@
// Copyright (c) 2026 The Bitcoin Core developers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it's similar to Alertpopup. cannot make a shared component between them or reuse AlertPopup?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to show the list of banned peers in a modal view so that we show them without pushing a new view. Hence the popup suffix. It's not related to Alertpopup :)

background: Rectangle { color: Theme.color.neutral0 }

function unavailable(value) {
return value === undefined || value === null || String(value).length === 0 || value === "N/A"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PeerDetailsModel::mappedAS() and permission() return tr("N/A"), which is
translated. Under a German or Spanish locale the comparison never matches, so
those rows show the translated "N/A" instead of the em dash the rest of the page
uses.

Fix it in the model. Let C++ report "no value" and let QML decide how to render
it:

// qml/models/peerdetailsmodel.h
QString mappedAS() const { return m_combinedStats->nodeStats.m_mapped_as != 0 ? QString::number(m_combinedStats->nodeStats.m_mapped_as) : QString{}; }
QString permission() const {
    if (m_combinedStats->nodeStats.m_permission_flags == NetPermissionFlags::None) {
        return {};
    }
    ...
}

Then drop || value === "N/A" from unavailable(). startingHeight() returns
tr("N/A") too and has the same problem.

return String(details.mappedAS).indexOf("AS") === 0 ? details.mappedAS : "AS" + details.mappedAS
}
function heightValue(value) {
return unavailable(value) || Number(value) < 0 ? "—" : Number(value).toLocaleString(Qt.locale(), "f", 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: There are a lot of emdashes. honestly I dont like it and I don't think people like it after the AI. cannot replace them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Em-dashes is probably the right thing to do here.
We do have precedent in using em-dash for empty values. See bullet 2 in #807.
(AI ruined em-dashes for everyone)

Comment thread qml/pages/node/Peers.qml
@@ -1,4 +1,4 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Copyright (c) 2023-2026 The Bitcoin Core developers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot reuse the network charts in settings page here?

Image

it would be really cool (I love charts =D)

@uqlidi

uqlidi commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Fix broken CIs please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants